package cn.panshi.mongocdc;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import org.springframework.data.mongodb.core.index.Indexed;

import lombok.extern.slf4j.Slf4j;

@SuppressWarnings({ "rawtypes", "unchecked" })
@Slf4j
public class ReflectionUtils {

	public static List<Field> fetchFieldsWithUniqueIndex(Class docClazz) {
		List<Field> list = new ArrayList<>();
		for (Field f : docClazz.getDeclaredFields()) {
			if (f.isAnnotationPresent(Indexed.class)) {
				Indexed indexed = f.getAnnotation(Indexed.class);
				if (indexed.unique()) {
					f.setAccessible(true);
					list.add(f);
				}
			}
		}

		Class<?> superclass = docClazz.getSuperclass();
		while (!superclass.equals(Object.class)) {
			for (Field f : superclass.getDeclaredFields()) {
				if (f.isAnnotationPresent(Indexed.class)) {
					Indexed indexed = f.getAnnotation(Indexed.class);
					if (indexed.unique()) {
						f.setAccessible(true);
						list.add(f);
					}
				}
			}
			superclass = superclass.getSuperclass();
		}

		return list;
	}

	public static List<Field> fetchFieldWithAnnotationClass(Class targetClazz, Class annClazz) {
		List<Field> list = new ArrayList<>();
		for (Field f : targetClazz.getDeclaredFields()) {
			if (f.isAnnotationPresent(annClazz)) {
				f.setAccessible(true);
				list.add(f);
			}
		}

		Class<?> superclass = targetClazz.getSuperclass();
		while (!superclass.equals(Object.class)) {
			for (Field f : superclass.getDeclaredFields()) {
				if (f.isAnnotationPresent(annClazz)) {
					f.setAccessible(true);
					list.add(f);
				}
			}
			superclass = superclass.getSuperclass();
		}

		return list;
	}

	public static Type[] getFieldGenericTypeArray(Field f) {
		if (f.getGenericType() instanceof ParameterizedType) {
			return ((ParameterizedType) f.getGenericType()).getActualTypeArguments();
		} else {
			return getClassGenericTypeArray(f.getType());
		}
	}

	/**
	 * 	获取第1个泛型class   http://www.blogjava.net/calvin/archive/2009/12/10/43830.html
	 */
	public static Type[] getClassGenericTypeArray(Class clazz) {
		return ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments();
	}

	public static String calcInvokeStackTrace(String memo) {
		Exception exception = new Exception(memo);
		return calcInvokeStackTrace(exception);
	}

	public static String calcInvokeStackTrace(Exception exception) {
		String rtn = exception.getStackTrace().toString();
		try {
			Writer writer = new StringWriter();
			PrintWriter printWriter = new PrintWriter(writer);
			exception.printStackTrace(printWriter);
			printWriter.flush();
			writer.flush();
			rtn = writer.toString();
			printWriter.close();
			writer.close();
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		} catch (Exception ex) {
		}
		return rtn;
	}

	public static List<Method> getMethodWithAnnotation(Class objClazz, Class annClazz) {
		List<Method> list = new ArrayList<>();
		for (Method m : objClazz.getDeclaredMethods()) {
			if (m.isAnnotationPresent(annClazz)) {
				m.setAccessible(true);
				list.add(m);
			}
		}
		return list;
	}

}